package com.mini.game.bus.userdata;

import com.mini.common.RedisService;
import com.mini.common.constant.RedisConstant;
import com.mini.common.util.JacksonUtil;
import com.mini.common.vo.ResData;
import com.mini.game.bus.event.CreateRoleEvent;
import com.mini.game.bus.event.GameEventPublisher;
import com.mini.game.bus.userdata.repository.GameUserCacheRepository;
import com.mini.game.bus.userdata.repository.GameUserRepository;
import com.mini.game.vo.ReqLogin;
import com.mini.game.vo.ResLogin;
import com.mini.game.vo.UserVo;
import org.apache.commons.lang.math.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 小鱼儿
 * @date 2020/11/17 23:26
 */
@Service
public class GameUserService {
    private final static Logger logger = LoggerFactory.getLogger(GameUserService.class);
    @Autowired
    private GameUserRepository gameUserRepository;
    @Autowired
    private GameUserCacheRepository gameUserCacheRepository;
    @Autowired
    private RedisService redisService;

    private Map<Long, Object> lockMap = new ConcurrentHashMap<>();

    public GameUser getGameUser(long userId) {
        return getGameUser(userId, false);
    }

    public GameUser getGameUser(long userId, boolean create) {
        GameUser gameUser = gameUserCacheRepository.cacheLoad(userId);
        if (gameUser == null) {
            if (create) {
                synchronized (getLock(userId)) {
                    gameUser = gameUserCacheRepository.cacheLoad(userId);
                    if (gameUser == null) {
                        String userName = (String) redisService.hget(RedisConstant.USER_ID_2_NAME, String.valueOf(userId));
                        if (userName == null) {
                            logger.error("getGameUser userId={} userName is null", userId);
                            return null;
                        }
                        UserVo userVo = redisService.hget(RedisConstant.USER_ID, userName, UserVo.class);
                        if (userVo == null) {
                            logger.error("getGame1User userId={} userVo is null", userId);
                            return null;
                        }
                        gameUser = addGameUser(userVo);
                    }
                }
            }
        }
        return gameUser;
    }


    public ResData login(long userId, String data) {
        ReqLogin reqLogin = JacksonUtil.stringToBean(data, ReqLogin.class);
        GameUser gameUser = getGameUser(userId);
        if (gameUser == null) {
            gameUser = getGameUser(userId, true);
            gameUser.setChannel(reqLogin.getChannel());
            gameUser.setLevel(RandomUtils.nextInt(100));
            gameUserCacheRepository.cacheUpdate(gameUser);
            GameEventPublisher.publishEvent(new CreateRoleEvent(userId));
        }
        ResLogin resLogin = new ResLogin();
        resLogin.setLevel(gameUser.getLevel());
        resLogin.setName(gameUser.getName());
        return ResData.buildResData(resLogin);
    }

    public GameUser addGameUser(UserVo userVo) {
        GameUser gameUser = new GameUser();
        gameUser.setCreateTime(System.currentTimeMillis());
        gameUser.setId(userVo.getUserId());
        gameUserCacheRepository.cacheInsert(gameUser);
        return gameUser;
    }


    public Object getLock(long userId) {
        Object lock = lockMap.get(userId);
        if (lock == null) {
            lock = new Object();
            Object lastValue = lockMap.putIfAbsent(userId, lock);
            if (lastValue != null) {
                lock = lastValue;
            }
        }
        return lock;
    }
}
